package com.ruoyi.common.utils.uniquekey;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 功能：
 *
 * @author：dell
 * @create：2020/6/5 17:12
 * @version：2020 Version：1.0
 * @company：老屋新房 Created with IntelliJ IDEA
 */

public class IdWorker implements IIdGenerator {
	private static final Logger logger = LoggerFactory.getLogger(IdWorker.class);
	private final long workerId;
	private final long epoch = 1403854494756L;
	private final long workerIdBits = 10L;
	private final long maxWorkerId;
	private long sequence;
	private final long sequenceBits;
	private final long workerIdShift;
	private final long timestampLeftShift;
	private final long sequenceMask;
	private long lastTimestamp;
	private static IdWorker flowIdWorker = new IdWorker(1L);

	private IdWorker(long workerId) {
		this.getClass();
		this.maxWorkerId = ~(-1L << 10);
		this.sequence = 0L;
		this.sequenceBits = 12L;
		this.getClass();
		this.workerIdShift = 12L;
		this.getClass();
		this.getClass();
		this.timestampLeftShift = 12L + 10L;
		this.getClass();
		this.sequenceMask = ~(-1L << 12);
		this.lastTimestamp = -1L;
		if (workerId <= this.maxWorkerId && workerId >= 0L) {
			this.workerId = workerId;
		} else {
			throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", this.maxWorkerId));
		}
	}

	public static IdWorker getFlowIdWorkerInstance() {
		return flowIdWorker;
	}

	public static IdWorker getFlowIdWorkerInstance(long workerId) {
		return new IdWorker(workerId);
	}

	public synchronized Long nextId() {
		long timestamp = System.currentTimeMillis();
		if (this.lastTimestamp == timestamp) {
			this.sequence = this.sequence + 1L & this.sequenceMask;
			if (this.sequence == 0L) {
				timestamp = this.tilNextMillis(this.lastTimestamp);
			}
		} else {
			this.sequence = 0L;
		}

		if (timestamp < this.lastTimestamp) {
			logger.error("clock moved backwards.Refusing to generate id for {} milliseconds", this.lastTimestamp - timestamp);
			try {
				throw new Exception(String.format("clock moved backwards.Refusing to generate id for %d milliseconds", this.lastTimestamp - timestamp));
			} catch (Exception e) {
				e.printStackTrace();
			}
			return null;
		} else {
			this.lastTimestamp = timestamp;
			this.getClass();
			return timestamp - 1403854494756L << (int)this.timestampLeftShift | this.workerId << (int)this.workerIdShift | this.sequence;
		}
	}

	private long tilNextMillis(long lastTimestamp) {
		long timestamp;
		for(timestamp = System.currentTimeMillis(); timestamp <= lastTimestamp; timestamp = System.currentTimeMillis()) {
			;
		}

		return timestamp;
	}
}